package com.cyy.view

import com.cyy.app.DraggingStyles
import com.cyy.app.SelectingStyles
import com.cyy.controller.*
import com.cyy.model.MyCircle
import com.cyy.model.Point
import javafx.animation.AnimationTimer
import javafx.animation.RotateTransition
import javafx.collections.FXCollections
import javafx.concurrent.Task
import javafx.geometry.Insets
import javafx.geometry.Point2D
import javafx.geometry.Pos
import javafx.scene.Group
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.control.Alert
import javafx.scene.control.TextField
import javafx.scene.control.TreeItem
import javafx.scene.control.TreeView
import javafx.scene.effect.DropShadow
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import javafx.scene.input.MouseEvent
import javafx.scene.layout.Pane
import javafx.scene.layout.Priority
import javafx.scene.paint.Color
import javafx.scene.shape.Circle
import javafx.scene.shape.Line
import javafx.scene.shape.Rectangle
import javafx.util.Duration
import tornadofx.*
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.net.URL
import java.time.LocalDate
import kotlin.math.abs

class MyView : View("My View") {
    val controller: MyController by inject()
    override val root = vbox {
        label(controller.dataForView)
        prefWidth = 568.0
        prefHeight = 320.0
    }
}

class MyFrag : Fragment("My Fragment") {
    val data = stringProperty()
    override val root = vbox {
        label(data)
        prefWidth = 568.0
        prefHeight = 320.0
    }

    override fun onDock() {
        data.value = params["data"] as String
    }
}

class ViewAndFragsDemoView : View("View and Fragments Demo") {

    val controller: MyController by inject()

    private val dataForFrags = stringProperty()

    override val root = vbox {

        menubar {
            menu("Windows") {
                item("View") {
                    action { openViewWindow() }
                }
                item("Fragment") {
                    action { openFragWindow() }
                }
            }
        }

        vbox {
            label("Opens the Singleton MyView")
            textfield(controller.dataForView)
            hbox {
                button("Open") {
                    action { openViewWindow() }
                }
                label("Shortcut: F1")
                alignment = Pos.CENTER_LEFT
                spacing = 4.0
            }

            separator()

            label("Opens a New MyFragment")
            textfield(dataForFrags)
            hbox {
                button("Open") {
                    action { openFragWindow() }
                }
                label("Shortcut: F2")
                alignment = Pos.CENTER_LEFT
                spacing = 4.0

            }

            prefHeight = 320.0
            prefWidth = 480.0

            padding = Insets(10.0)
            spacing = 4.0
        }
    }

    init {
        find<MyDispatcher>()
    }

    override fun onDock() {
        primaryStage.scene.addEventFilter(KeyEvent.KEY_PRESSED) {
            when (it.code) {
                KeyCode.F1 -> {
                    openViewWindow()
                    it.consume()
                }
                KeyCode.F2 -> {
                    openFragWindow()
                    it.consume()
                }
            }
        }
    }

    private fun openViewWindow() = fire(OpenWindowEvent(WINDOW_ID_VIEW, ""))

    private fun openFragWindow() = fire(OpenWindowEvent(WINDOW_ID_FRAGMENT, dataForFrags.value ?: ""))
}


class CancelView : View("Cancel App") {
    val URL_BASE = "https://courses.bekwam.net/public_tutorials/images/"
    val status: TaskStatus by inject()
    val imageViews = mutableListOf<ImageView>().asObservable()
    var runningTask: Task<MutableList<ByteArray>>? = null

    val imageList = listOf(
            "bkcourse_rc_charging.png",
//            "bkcourse_rc_circuit.JPG",
//            "bkcourse_rc_circuit_annotated.png",
//            "bkcourse_rc_circuit_schem.png",
//            "bkcourse_rc_charging.png",
//            "bkcourse_greatgrid_fx.png",
//            "bkcourse_greatgrid_spec.png",
//            "bkcourse_greatgrid_swing.png",
//            "bkcourse_flatwinapp_ea.png",
//            "bkcourse_flatwinapp_final.png",
//            "bkcourse_flatwinapp_initial_hier.png",
//            "bkcourse_flatwinapp_mpu_gtk.png",
//            "bkcourse_flatwinapp_mpu_mac.png",
//            "bkcourse_flatwinapp_mpu_win.png",
//            "bkcourse_flatwinapp_snagit.png",
//            "bkcourse_kstudent_001_badcomment.png",
//            "bkcourse_kstudent_001_mycomment.png",
//            "bkcourse_kstudent_001_nocomment.png",
//            "bkcourse_kstudent_001_println_docs.png",
//            "bkcourse_kstudent_001_trykotlinlang.png",
//            "bkcourse_kstudent_001_twoprintlns.png",
            "bkcourse_kstudent_001_twoprintlns_results.png"
    )

    override val root = vbox {

        vbox {
            button("Fetch Images") {
                disableWhen { status.running }
                action {
                    runningTask = runAsync {
                        val imageBytesList = mutableListOf<ByteArray>()
                        for ((index, url) in imageList.withIndex()) {
                            updateMessage("Loading $url...")
                            updateProgress((index + 1.0) / imageList.size, 1.0)
                            if (!isCancelled) {
                                imageBytesList.add(getBytes(URL_BASE + url))
                            }
                        }
                        imageBytesList
                    } ui {
                        addImages(it)
                    } fail {

                        val alert = Alert(Alert.AlertType.ERROR, it.message)
                        alert.headerText = "Error Loading Images"
                        alert.showAndWait()

                    } cancel {

                        val alert = Alert(Alert.AlertType.INFORMATION, "Operation Cancelled")
                        alert.headerText = "Loading Images"
                        alert.showAndWait()

                    }
                }
            }

            scrollpane {
                flowpane {
                    children.bind(imageViews, { it })

                    prefWidth = 667.0
                    prefHeight = 336.0

                    vgap = 10.0
                    hgap = 10.0
                }
                vgrow = Priority.ALWAYS
                padding = Insets(10.0)
            }

            vgrow = Priority.ALWAYS

            spacing = 10.0
            padding = Insets(10.0)
        }
        separator()
        hbox {
            visibleProperty().bind(status.running)
            progressbar(status.progress)
            button("Cancel") {
                action {
                    doCancel()
                }
            }
            label(status.message)

            alignment = Pos.CENTER_LEFT
            spacing = 4.0

            padding = Insets(0.0, 10.0, 10.0, 10.0)
        }

        spacing = 10.0

        prefWidth = 736.0
        prefHeight = 414.0

    }

    private fun doCancel() {
        if (runningTask != null && runningTask!!.isRunning()) {
            runningTask!!.cancel()
        }
    }

    private fun getBytes(url: String): ByteArray {

        val BUF_SIZE = 100_000 // 100k
        val byteArray = ByteArray(BUF_SIZE)
        val baos = ByteArrayOutputStream()
        val byteStream = URL(url).openStream()

        try {
            var nbytes = byteStream.read(byteArray)
            baos.write(byteArray, 0, nbytes)

            while (nbytes > 0) {
                nbytes = byteStream.read(byteArray)
                if (nbytes > 0) {
                    baos.write(byteArray, 0, nbytes)
                }
            }

            return baos.toByteArray()

        } finally {
            byteStream.close()
            baos.close()
        }
    }

    private fun addImages(imageBytesList: List<ByteArray>) {

        val images = imageBytesList.map {
            Image(ByteArrayInputStream(it), 200.0, 200.0, true, true)
        }

        imageViews.clear()
        imageViews.addAll(images.map { ImageView(it) })
    }
}

class Todo(descr: String = "New Item", completed: Boolean = false, completedBy: LocalDate? = null) {
    val descrProperty = stringProperty(descr)
    val completedProperty = booleanProperty(completed)
    val completedByProperty = objectProperty<LocalDate>(completedBy)
}

class TodoItemViewModel : ItemViewModel<Todo>() {
    val selectedDescr = bind(Todo::descrProperty)
    val selectedCompleted = bind(Todo::completedProperty)
    val selectedCompletedBy = bind(Todo::completedByProperty)

    init {
        autocommitProperties.addAll(selectedDescr, selectedCompleted, selectedCompletedBy)
    }
}

class ListNavController : Controller() {

    val data = mutableListOf<Todo>().asObservable()

    fun newItem() {
        data.add(Todo())
    }
}

class ListDetailsView : View("List Nav - Details") {

    val mainView: ListNavView by inject()
    val todoItemViewModel: TodoItemViewModel by inject()

    var tf: TextField by singleAssign()

    override val root = vbox {

        button("<") {
            action {
                this@ListDetailsView.replaceWith(
                        mainView,
                        ViewTransition.Slide(Duration.seconds(0.5), tornadofx.ViewTransition.Direction.RIGHT)
                )
            }
        }
        form {
            fieldset {
                field("Descr") {
                    tf = textfield(todoItemViewModel.selectedDescr)
                }
                field("Completed") {
                    checkbox {
                        bind(todoItemViewModel.selectedCompleted)
                    }
                }
                field("Completed By") {
                    datepicker(todoItemViewModel.selectedCompletedBy)
                }
            }
        }

        spacing = 4.0
        paddingTop = 4.0
    }

    override fun onDock() = tf.requestFocus()
}

class TodoListItemFragment : ListCellFragment<Todo>() {
    val model = TodoItemViewModel().bindTo(this)

    override val root = hbox {
        checkbox(property = model.selectedCompleted)
        vbox {
            label(model.selectedDescr)
            label(model.selectedCompletedBy, converter = javafx.util.converter.LocalDateStringConverter())
        }
    }
}

class ListNavView : View("List Nav") {

    val c: ListNavController by inject()
    val detailsView: ListDetailsView by inject()
    val todoItemViewModel: TodoItemViewModel by inject()

    override val root = vbox {
        button("+") { action { c.newItem() } }
        listview(c.data) {
            bindSelected(todoItemViewModel)
            onDoubleClick {
                this@ListNavView.replaceWith(detailsView, ViewTransition.Slide(Duration.seconds(0.5)))
            }
            cellFragment(TodoListItemFragment::class)
            vgrow = Priority.ALWAYS
        }

        prefHeight = 480.0
        prefWidth = 320.0
        spacing = 4.0
        paddingTop = 4.0
    }
}

class SlideShowView : View("Slide Show") {

    private val imageURLs = arrayOf(
            Image("http://www.xuchang.gov.cn/CommonDataPics/4840a253-f83d-42f8-8541-b09263f594bd/4840a253-f83d-42f8-8541-b09263f594bd.jpg"),
            Image("http://www.xuchang.gov.cn/CommonDataPics/a46c4092-bd02-4868-ba3f-e429c4e22e4a/a46c4092-bd02-4868-ba3f-e429c4e22e4a.jpg"),
            Image("http://www.xuchang.gov.cn/CommonDataPics/231eef69-9853-4d69-9760-20e5b6e88171/231eef69-9853-4d69-9760-20e5b6e88171.jpg")
    )

    override val root = vbox {
        pagination(imageURLs.size) { setPageFactory { pageIndex -> ImageView(imageURLs[pageIndex]) } }
    }
}


class MovingView : View("Moving App") {

    val rectangles = mutableListOf<Rectangle>()

    var selectedRectangle: Rectangle? = null
    var selectedOffset: Point2D? = null

    val positionMessage = stringProperty("")

    enum class XFormType { NONE, SCALE, ROTATE }

    override val root = vbox {

        anchorpane {
            pane {

                fun createRectangle(startX: Double, f: Color, xform: XFormType = XFormType.NONE): Rectangle {
                    return rectangle(startX, 100.0, 50.0, 50.0) {
                        fill = f
                        stroke = Color.BLACK
                        rectangles.add(this)  // for convenience
                        layoutX = 25.0
                        layoutY = 25.0
                        when (xform) {
                            XFormType.SCALE -> {
                                scaleX = 2.0
                                scaleY = 2.0
                            }
                            XFormType.ROTATE -> {
                                rotate = 45.0
                            }
                        }
                    }
                }

                createRectangle(100.0, Color.BLUE)
                createRectangle(300.0, Color.YELLOW, XFormType.SCALE)
                createRectangle(500.0, Color.GREEN, XFormType.ROTATE)

                anchorpaneConstraints {
                    topAnchor = 0.0
                    bottomAnchor = 0.0
                    rightAnchor = 0.0
                    leftAnchor = 0.0
                }

                addEventFilter(MouseEvent.MOUSE_PRESSED, ::startDrag)
                addEventFilter(MouseEvent.MOUSE_DRAGGED, ::drag)
                addEventFilter(MouseEvent.MOUSE_RELEASED, ::endDrag)
            }

            vboxConstraints {
                vgrow = Priority.ALWAYS
            }
        }

        label(positionMessage) {
            padding = Insets(2.0)
        }

        padding = Insets(2.0)
    }

    private fun startDrag(evt: MouseEvent) {

        rectangles
                .filter {
                    val mousePt = it.sceneToLocal(evt.sceneX, evt.sceneY)
                    it.contains(mousePt)
                }
                .firstOrNull()
                .apply {
                    if (this != null) {

                        selectedRectangle = this

                        val mp = this.parent.sceneToLocal(evt.sceneX, evt.sceneY)
                        val vizBounds = this.boundsInParent

                        selectedOffset = Point2D(
                                mp.x - vizBounds.minX - (vizBounds.width - this.boundsInLocal.width) / 2,
                                mp.y - vizBounds.minY - (vizBounds.height - this.boundsInLocal.height) / 2
                        )
                    }
                }
    }

    private fun drag(evt: MouseEvent) {

        val mousePt: Point2D = (evt.source as Pane).sceneToLocal(evt.sceneX, evt.sceneY)
        if (selectedRectangle != null && selectedOffset != null) {

            selectedRectangle!!.relocate(
                    mousePt.x - selectedOffset!!.x,
                    mousePt.y - selectedOffset!!.y)

            positionMessage.value =
                    "Last Selection: Mouse (${mousePt.x}, ${mousePt.y}) Moving To (${mousePt.x - selectedOffset!!.x}, ${mousePt.y - selectedOffset!!.y})"

        }
    }

    private fun endDrag(evt: MouseEvent) {
        evt.x
        selectedRectangle = null
        selectedOffset = null
    }
}


class SelectingView : View("Selecting App") {

    var workArea: Pane by singleAssign()

    val circles = mutableListOf<Circle>()

    val selectedCircles = FXCollections.observableArrayList<String>()

    var lassoRect: Rectangle by singleAssign()

    var initDrag = false
    var dragStart: Point2D? = null

    override val root = hbox {
        anchorpane {

            workArea = pane {

                fun createCircle(centerX: Int, centerY: Int, c: Color, prop: String): Circle {
                    return circle(centerX, centerY, 50) {
                        fill = c
                        addClass(SelectingStyles.circleItem)
                        circles.add(this)
                        properties["circleColor"] = prop
                    }
                }

                addClass(SelectingStyles.workArea)

                createCircle(100, 100, Color.RED, "RED")
                createCircle(220, 100, Color.BLUE, "BLUE")
                createCircle(100, 220, Color.GREEN, "GREEN")
                createCircle(220, 220, Color.YELLOW, "YELLOW")

                label("Ctrl, Shift, or Drag to Multi-Select") {
                    padding = Insets(2.0)
                }

                lassoRect = rectangle {
                    isVisible = false
                    addClass(SelectingStyles.lassoRect)
                }

                anchorpaneConstraints {
                    topAnchor = 0.0
                    bottomAnchor = 0.0
                    leftAnchor = 0.0
                    rightAnchor = 0.0
                }

                addEventFilter(MouseEvent.MOUSE_PRESSED, ::press)
                addEventFilter(MouseEvent.MOUSE_DRAGGED, ::lasso)
                addEventFilter(MouseEvent.MOUSE_RELEASED, ::stopLasso)
            }

            padding = Insets(10.0)

            hboxConstraints {
                hgrow = Priority.ALWAYS
            }
        }

        vbox {
            listview(selectedCircles)

            padding = Insets(10.0)
        }
    }

    private fun lasso(evt: MouseEvent) {
        if (!initDrag) {
            lassoRect.isVisible = true
            dragStart = workArea.sceneToLocal(evt.sceneX, evt.sceneY)
            if (dragStart != null) {
                lassoRect.relocate(dragStart!!.x, dragStart!!.y)
            }
            initDrag = true
        }

        // find width and height; negatives ok?
        val currPos = workArea.sceneToLocal(evt.sceneX, evt.sceneY)
        if (dragStart != null) {

            val w = currPos.x - dragStart!!.x
            val y = currPos.y - dragStart!!.y

            lassoRect.width = abs(w)
            lassoRect.height = abs(y)

            if (w < 0 || y < 0) { // dragging left or up
                lassoRect.relocate(currPos.x, currPos.y)
            }
        }
    }

    private fun stopLasso(evt: MouseEvent) {
        evt.x
        if (initDrag) {  // in drag operation

            lassoRect.isVisible = false

            val lassoBounds = lassoRect.boundsInParent

            circles
                    .filter {
                        lassoBounds.contains(it.boundsInParent)
                    }
                    .forEach {
                        selectCircle(it)
                    }
        }

        initDrag = false
        dragStart = null
    }

    private fun press(evt: MouseEvent) {

        if (!evt.isControlDown && !evt.isShiftDown) {

            circles
                    .forEach {
                        if (it.hasClass(SelectingStyles.selected)) {
                            it.removeClass(SelectingStyles.selected)
                        }
                    }

            selectedCircles.clear()
        }

        circles.filter {
            val mousePt: Point2D = it.sceneToLocal(evt.sceneX, evt.sceneY)
            it.contains(mousePt)
        }.firstOrNull()
                .apply {
                    if (this != null) {
                        if (this.hasClass(SelectingStyles.selected)) {
                            this.removeClass(SelectingStyles.selected)
                            selectedCircles.remove(this.properties["circleColor"] as String)
                        } else {
                            selectCircle(this)
                        }
                    }
                }
    }

    private fun selectCircle(circ: Circle) {
        circ.addClass(SelectingStyles.selected)
        selectedCircles.add(circ.properties["circleColor"] as String)
    }
}

class DraggingView : View("Dragging App") {
    private val RECTANGLE_HEIGHT = 50.0
    private val RECTANGLE_WIDTH = 50.0

    private var draggingColor: Color? = null

    private val toolboxItems = mutableListOf<Node>()

    private var inflightRect: Rectangle by singleAssign()

    private var toolbox: Parent by singleAssign()

    private var workArea: Pane by singleAssign()

    override val root = hbox {

        addClass(DraggingStyles.wrapper)

        toolbox = vbox {

            fun createToolboxItem(c: Color): Rectangle {
                return rectangle(width = RECTANGLE_WIDTH, height = RECTANGLE_HEIGHT) {
                    fill = c
                    properties["rectColor"] = c
                    addClass(DraggingStyles.toolboxItem)
                }
            }

            add(createToolboxItem(Color.RED))
            add(createToolboxItem(Color.BLUE))
            add(createToolboxItem(Color.YELLOW))

            spacing = 10.0
            padding = Insets(10.0)
            alignment = Pos.CENTER

            hboxConstraints {
                hgrow = Priority.NEVER
            }
        }
        anchorpane {
            workArea = pane {

                addClass(DraggingStyles.workArea)

                anchorpaneConstraints {
                    leftAnchor = 0.0
                    topAnchor = 0.0
                    rightAnchor = 0.0
                    bottomAnchor = 0.0
                }

                inflightRect = rectangle(0, 0, RECTANGLE_WIDTH, RECTANGLE_HEIGHT) {
                    isVisible = false
                    opacity = 0.7
                    effect = DropShadow()
                }

                add(inflightRect)
            }

            hboxConstraints {
                hgrow = Priority.ALWAYS
            }

        }
        vboxConstraints {
            vgrow = Priority.ALWAYS
        }

        padding = Insets(10.0)
        spacing = 10.0

        addEventFilter(MouseEvent.MOUSE_PRESSED, ::startDrag)
        addEventFilter(MouseEvent.MOUSE_DRAGGED, ::animateDrag)
        addEventFilter(MouseEvent.MOUSE_EXITED, ::stopDrag)
        addEventFilter(MouseEvent.MOUSE_RELEASED, ::stopDrag)
        addEventFilter(MouseEvent.MOUSE_RELEASED, ::drop)

    }

    init {
        toolboxItems.addAll(toolbox.childrenUnmodifiable)
    }

    private fun startDrag(evt: MouseEvent) {

        toolboxItems
                .filter {
                    val mousePt: Point2D = it.sceneToLocal(evt.sceneX, evt.sceneY)
                    it.contains(mousePt)
                }
                .firstOrNull()
                .apply {
                    if (this != null) {
                        draggingColor = this.properties["rectColor"] as Color
                    }
                }

    }

    private fun animateDrag(evt: MouseEvent) {

        val mousePt = workArea.sceneToLocal(evt.sceneX, evt.sceneY)
        if (workArea.contains(mousePt)) {

            // highlight the drop target (hover doesn't work)
            if (!workArea.hasClass(DraggingStyles.workAreaSelected)) {
                workArea.addClass(DraggingStyles.workAreaSelected)
            }

            // animate a rectangle so that the user can follow
            if (!inflightRect.isVisible) {
                inflightRect.isVisible = true
                inflightRect.fill = draggingColor
            }

            inflightRect.relocate(mousePt.x, mousePt.y)
        }

    }

    private fun stopDrag(evt: MouseEvent) {
        evt.x
        if (workArea.hasClass(DraggingStyles.workAreaSelected)) {
            workArea.removeClass(DraggingStyles.workAreaSelected)
        }
        if (inflightRect.isVisible) {
            inflightRect.isVisible = false
        }
    }

    private fun drop(evt: MouseEvent) {

        val mousePt = workArea.sceneToLocal(evt.sceneX, evt.sceneY)
        if (workArea.contains(mousePt)) {
            if (draggingColor != null) {
                val newRect = Rectangle(RECTANGLE_WIDTH, RECTANGLE_HEIGHT, draggingColor)
                workArea.add(newRect)
                newRect.relocate(mousePt.x, mousePt.y)

                inflightRect.toFront() // don't want to move cursor tracking behind added objects
            }
        }

        draggingColor = null
    }

}

val mutableMap = mutableMapOf<String, String>()

class TreeviewDemo : Fragment("Treeview") {
    var tv = TreeView<String>()
    var nodes = TreeItem<String>()
    val fname = stringProperty()
    val content = stringProperty()

    override val root = vbox {
        button("load tree") {
            action {
                val d = chooseDirectory {}
                runAsync {
                    nodes = getNodesForDirectory(d?.absoluteFile)
                } ui {
                    tv.root = nodes
                }
            }
        }
        hbox {
            tv = treeview<String> {
                root = TreeItem("")
                bindSelected(fname)
                selectionModel.selectedItemProperty().addListener { _ ->
                    val fpath = mutableMap.get(selectionModel.selectedItem!!.value)
                    content.value = File(fpath).readText()
                }
            }
            textarea(content) {

            }
        }
    }

}

//Returns a TreeItem representation of the specified directory
fun getNodesForDirectory(directory: File?): TreeItem<String> {
    val root = TreeItem<String>(directory?.getName())
    directory?.listFiles()?.forEach {
        if (it.isDirectory()) { //Then we call the function recursively
            root.children.add(getNodesForDirectory(it))
        } else {
            root.children.add(TreeItem<String>(it.getName()))
        }
        mutableMap.put(it.name, it.absolutePath)
    }
    return root
}

class AnimationDemo : Fragment("Animation") {

    override val root = group {
        val circle = Circle(200.0, 200.0, 10.0)

        class AniTimer : AnimationTimer() {
            var lastTime = 0L
            var step = 1
            override fun handle(now: Long) {
                if ((now - lastTime) > 10000000) {
                    lastTime = now
                } else {
                    return
                }
                if (circle.radius > 200 || circle.radius < 0) {
                    step *= -1
                }
                circle.radius = circle.radius + step
            }
        }

        class ColorChanger : AnimationTimer() {
            var lastTime = 0L
            var red = 10
            var green = 10
            var blue = 60
            var direction = 1
            override fun handle(now: Long) {
                if ((now - lastTime) > 10000000) {
                    lastTime = now
                } else {
                    return
                }
                circle.fill = Color.rgb(red, green, blue)
                if (red > 254 || red < 1) {
                    direction *= -1
                    if (blue > 244) {
                        blue = 1
                    }
                    blue += 2
                    if (green > 244) {
                        green = 1
                    }
                    green += 10
                }
                red += direction
            }
        }
        add(circle)

        ColorChanger().start()
        AniTimer().start()
    }
}

class AnimationDemo1 : Fragment() {

    override val root = group {
        val root1 = this
        val circle = arrayListOf<MyCircle>()
        repeat(10) {
            circle.add(MyCircle((Math.random() * 500 + 50).toInt(), (Math.random() * 500 + 50).toInt(), Math.random() * 40 + 10, 1))
        }
        //        for(i in 0..10){
//            circle.add(MyCircle(Math.random()*500+50), (int) (Math.random()*500+50), (int) (Math.random()*40+10), 1);
//        }
        class AniTimer : AnimationTimer() {
            var lastTime = 0L
            override fun handle(now: Long) {
                if ((now - lastTime) > 30000000) {
                    lastTime = now
                } else {
                    return
                }
                root1.children.clear()
                circle.forEach {
                    root1.add(it.nextCircle)
                }
            }
        }
        AniTimer().start()
    }
}

//ffmpeg -f image2 -r 1 -i 'a1 %02d.png' -vcodec mpeg4 demo.mp4
//ffmpeg -ss 00:00:01 -t 3 -i demo.mp4 -vf crop=iw:ih*2/3 -s 320x240 -r 7 demo.gif
//ffmpeg -f image2 -r 1 -i 'a1 %02d.png' -vf crop=iw:ih*2/3 -s 320x240 -r 7 demo.gif
class AnimationDemo2 : Fragment() {

    override val root = stackpane {
        for (i in 0..180 step 10) {
            val a = Rectangle(450.0, 450.0)
            a.rotate = i.toDouble()
            a.fill = Color.rgb(i + 70, i + 20, i + 60)
            val transition = RotateTransition(Duration.seconds(10.0), a)
            transition.setFromAngle(i.toDouble())
            transition.setToAngle(360.0)
            transition.setCycleCount(100)
            transition.setAutoReverse(true)
            transition.play()
            add(a)
        }
        imageview {
            image = Image("Java_logo.png")
        }
    }
}

class RecursiveCallTree : Fragment("RecursiveCallTree") {
    override val root = group {
        val root1 = this
        val start = Point(400.0, 600.0)
        val level= intProperty()
        val levelList= listOf<Int>(1,3,5,10,15,20)
        hbox {
            button("draw tree") {
                action {
                    run {
                        drawTree(root1, start, 90.0, 10)
                    }
                }
            }
            combobox(level,levelList)
        }
    }

   fun drawTree(group: Group, p0: Point, angle: Double, level: Int) {
        if (level <= 0) {
            return
        }
        val destination = p0.getDestination(10F, angle, level)
        val line = Line(p0.x, p0.y, destination.x, destination.y)
        line.setStrokeWidth(level.toDouble())
        if (level > 7) {
            line.setStroke(Color.BROWN)
        } else if (level > 3) {
            line.setStroke(Color.GREEN)
        } else {
            line.setStroke(Color.LIMEGREEN)
        }
        group.add(line)
        drawTree(group, destination, angle - 20.0 - Math.random() * 10, level - 1)
        drawTree(group, destination, angle - 5, level - 1)
        drawTree(group, destination, angle + 20.0 + Math.random() * 20, level - 1)
    }
}




